import compose from '../../../common/compose'
import Layer from './RouterLayer'

export function Router(opts = {}) {
  // 支持无new直接调用
  if(!(this instanceof Router)) return new Router()

  this.opts = opts
  this.methods = this.opts.methods || [
    'HEAD',
    'OPTIONS',
    'GET',
    'PUT',
    'PATCH',
    'POST',
    'DELETE'
  ]
  this.params = {}
  this.layers = []
}

// HTTP动词函数
const methods = [
  'get',
  'post',
  'put',
  'delete',
  'patch',
  'head',
  'options',
  'all',
  // 'trace',
  // 'copy',
  // 'lock',
  // 'mkcol',
  // 'move',
  // 'purge',
  // 'propfind',
  // 'proppatch',
  // 'unlock',
  // 'report',
  // 'mkactivity',
  // 'checkout',
  // 'merge',
  // 'm-search',
  // 'notify',
  // 'subscribe',
  // 'unsubscribe',
  // 'search',
  // 'connect'
]

for(let i = 0; i < methods.length; i++) {
  const method = methods[i]

  // router.get('/api/users', (ctx) => {}, (ctx) => {})
  Router.prototype[method] = function(path, ...middlewares) {
    this.register(path, method, ...middlewares)

    return this
  }
}

// 【注册路由】主要是构建路由的数据结构，具体来说就是创建很多layer，
// 每个layer上保存具体的path，methods，和回调函数。
Router.prototype.register = function(path, method, ...middlewares) {
  const route = new Layer(path, method, ...middlewares)
  this.layers.push(route)
  return route
}

// router 作为中间件
Router.prototype.routes = function() {
  const router = this
  const dispatch = (ctx, next) => {
    ctx.router = router


    const matchedLayers = this.match(ctx.pathname, ctx.method) // 获取所有匹配的layer
    if(matchedLayers.length === 0) return next() // 如果一个layer都没匹配上，直接返回，并执行下一个Koa中间件
    //
    // 将所有layer的回调函数都合并到一个数组layerChain里面去
    const matchedHandles = matchedLayers.reduce((memo, layer) => memo.concat(layer.handles), [])
    return compose(matchedHandles)(ctx, next)

    // const path = router.opts.routerPath || ctx.routerPath || ctx.path
    // const layerChain = matchedLayers.reduce(function(memo, layer) {
    //   memo.push(function(ctx, next) {
    //     ctx.captures = layer.captures(path, ctx.captures)
    //     ctx.params = ctx.request.params = layer.params(path, ctx.captures, ctx.params)
    //     ctx.routerPath = layer.path
    //     ctx._matchedRoute = layer.path
    //     return next()
    //   })
    //   return memo.concat(layer.stack)
    // }, [])
    // // 将 matchedHandles 数组合并成一个方法，传入参数是中间件参数ctx, next
    // return compose(layerChain)(ctx, next)
  }

  return dispatch
}

// 匹配路由就是去遍历所有的layer，找出匹配的layer，将回调方法拿来执行。
// 一个路由可能匹配多个layer和回调函数，执行时使用compose将这些匹配的回调函数串起来，一个一个执行。
// 需要注意的是，如果一个路由匹配了多个回调函数，前面的回调函数必须调用next()才能继续走到下一个回调函数。
Router.prototype.match = function(path, method) {
  // 构建一个结构来保存匹配结果，最后返回的也是这个matched
  const matchedLayers = []

  // 循环layers来进行匹配
  for(const layer of this.layers) {
    // 匹配的时候调用的是layer的实例方法match
    if(layer.method === method && layer.match(path)) {
      matchedLayers.push(layer)
    }
  }

  return matchedLayers
}

Router.prototype.matchHandles = function(path, method) {
  return this.layers
    .filter(layer => layer.method === method && layer.match(path))
    .flatMap(layer => layer.handles)
  // let matchHandles = []
  // for(const layer of this.layers) {
  //   // 匹配的时候调用的是layer的实例方法match
  //   if(layer.method === method && layer.match(path)) {
  //     matchHandles = matchHandles.concat(layer.handles)
  //   }
  // }
  //
  // return matchHandles
}

// https://github.com/koajs/router/blob/master/lib/router.js
// http://www.zuo11.com/blog/2020/8/allowedMethods_use.html
Router.prototype.allowedMethods = function(options = {}) {
  return (ctx, next) => {}
}
